package com.jack.payment.service.basic.impl;

import com.jack.payment.cache.CacheRedisServiceImpl;
import com.jack.payment.constant.ResultHintConstant;
import com.jack.payment.constant.SettingRuleConstant;
import com.jack.payment.constant.enums.AccountVerifyCodeEnum;
import com.jack.payment.dao.user.UserAuthDao;
import com.jack.payment.dao.user.UserDao;
import com.jack.payment.dao.user.UserDeviceDao;
import com.jack.payment.dao.user.UserSettingDao;
import com.jack.payment.entity.business.SendEmailBo;
import com.jack.payment.entity.common.BusinessException;
import com.jack.payment.entity.filter.UserFilter;
import com.jack.payment.entity.generate.user.UserAuthModel;
import com.jack.payment.entity.generate.user.UserDeviceModel;
import com.jack.payment.entity.generate.user.UserModel;
import com.jack.payment.entity.generate.user.UserSettingModel;
import com.jack.payment.entity.request.BasicAccountModel;
import com.jack.payment.util.auth.AuthUtils;
import com.jack.payment.util.common.EmailMessageUtil;
import com.jack.payment.util.common.StringUtil;
import com.jack.payment.util.common.TimeUtil;
import com.jack.payment.util.network.IP2RegionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

@Service
public class UserServiceImpl {
    private Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserSettingDao userSettingDao;
    @Autowired
    private CacheRedisServiceImpl cacheRedisService;
    @Autowired
    private EmailMessageUtil emailMessageUtil;
    @Autowired
    private UserAuthDao userAuthDao;
    @Autowired
    private UserDeviceDao userDeviceDao;


    /**
     * 根据用户id 获取指定用户的详细信息
     * @param userId
     * @return
     */
    public UserModel getAppointIdAccountInfo(String userId) throws BusinessException{
        if (StringUtil.isEmpty(userId)) {
            log.warn("查询用户不能未空字符串");
            throw new BusinessException(ResultHintConstant.BASIC_DATA_DROP);
        }
        UserModel userModel = userDao.userBasicInfo(userId);
        if (userModel == null) {
            log.warn("{} 该用户在系统不存在", userId);
            throw new BusinessException(ResultHintConstant.DATA_NOT_EXIST);
        }
        return userModel;
    }

    /**
     * 根据不同类型 查询出账号是否存在本系统
     * @param account 账号
     * @param source  类型
     * @return
     */
    public UserModel getAppointUserAccountInfo(String account,
                                               Integer source) {
        return userDao.userLogin(account, source);
    }

    /**
     * 获取指定用户的基础设置
     * @param userId
     * @return
     */
    public UserSettingModel getAppointUserSettingInfo(String userId) throws BusinessException {
        UserSettingModel getUserSetting = userSettingDao.getAppointUserSetting(userId);
        if (getUserSetting == null) {
            log.warn("未找到用户的基础设置信息, 此账号{}严重错误", userId);
            throw new BusinessException(ResultHintConstant.DATA_NOT_EXIST);
        }
        getUserSetting.setIpAddress(IP2RegionUtil.getAppointIpRegion(getUserSetting.getIpAddress()));
        return getUserSetting;
    }

    /**
     *  是否需要2fa验证之后才可进入系统
     * @param userId
     * @param deviceId
     * @return
     * @throws BusinessException
     */
    public boolean isNeed2FAVerify(String userId, String deviceId) throws BusinessException {
        UserFilter.UserDeviceFilter userDeviceFilterModel = new UserFilter.UserDeviceFilter();
        userDeviceFilterModel.setDeviceId(deviceId);
        userDeviceFilterModel.setUserId(userId);
        List<UserDeviceModel> userDeviceModelList = userDeviceDao.getAppointUserBindDeviceList(userDeviceFilterModel);
        if (userDeviceModelList.isEmpty()) {
            return true;
        }
        return false;
    }

    /**
     *  是否需要2fa验证之后才可进入系统
     * @param userId
     * @param deviceId
     * @return
     * @throws BusinessException
     */
    public SendEmailBo getRedisVerifyKeyInfo(UserModel userModel,
                                             BasicAccountModel.SendVerifyCodeModel sendVerifyCodeModel,
                                             AccountVerifyCodeEnum accountVerifyCodeEnum
                                             ) throws BusinessException {
        switch (accountVerifyCodeEnum) {
            case REGISTER, VERIFY -> {
                if (userModel != null) {
                   log.warn("该账号已在该系统中注册");
                   throw new BusinessException(ResultHintConstant.REGISTER_ACCOUNT_EXIST);
                }
            }
            case FORGET_PWD, BINDING -> {
                if (userModel == null) {
                    log.warn("该账号未在该系统中注册");
                    throw new BusinessException(ResultHintConstant.LOGIN_ACCOUNT_NOT);
                }
            }
            default -> {
                log.error("未找到合适的验证枚举信息");
                throw new BusinessException(ResultHintConstant.SYSTEM_CODE);
            }
        }
        return new SendEmailBo().builder()
                .redisKey(
                        accountVerifyCodeEnum.getRedisKey() + sendVerifyCodeModel.getSource() + ":" + sendVerifyCodeModel.getAccount())
                .subject(accountVerifyCodeEnum.getSubject())
                .text(accountVerifyCodeEnum.getText())
                .account(sendVerifyCodeModel.getAccount())
                .createTime(TimeUtil.getCurrentTime())
                .isVerifyEmail(true)
                .build();
    }

    /**
     * 修改用户登录密码
     * @param userId
     * @param pwd
     */
    public void updateUserLoginPwd(String userId, String pwd) {
        UserModel userModel = new UserModel();
        userModel.setId(userId);
        String salt = StringUtil.verifySalt();
        userModel.setPwd(AuthUtils.md5Hex(pwd, salt));
        userModel.setSalt(salt);
        userDao.updateUserBasicInfo(userModel);
    }

    /**
     * 发送验证码服务
     * @param sendEmailBo
     */
    public void sendVerifyCodeService(SendEmailBo sendEmailBo, String verifyCode) throws BusinessException {
        String systemSupportEmailStr = cacheRedisService.getCacheRuleContent(SettingRuleConstant.SUPPORT_EMAIL_LIST);
        List<String> systemSupportEmailList = Arrays.asList(systemSupportEmailStr.split(","));
        if (!StringUtil.verifyEmailLegal(sendEmailBo.getAccount(), systemSupportEmailList)) {
            log.warn("{} 是系统不支持的邮箱类型", sendEmailBo.getAccount());
            throw new BusinessException();
        }
        emailMessageUtil.sendEmail(new SendEmailBo().builder()
                .subject(cacheRedisService.getExternalMessageContent(sendEmailBo.getSubject()))
                .text(StringUtil.replaceStr(cacheRedisService.getExternalMessageContent(
                        sendEmailBo.getText()),
                        "{0}",
                        verifyCode))
                .createTime(TimeUtil.getCurrentTime())
                .account(sendEmailBo.getAccount())
                .isVerifyEmail(true)
                .build());
    }

    /**
     * 系统注册时, 注册用户的基础数据
     * @param userModel
     * @param userSettingModel
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void registerUser(UserModel userModel, UserSettingModel userSettingModel) {
        userDao.insertUserBasicInfo(userModel);
        userSettingDao.insertUserSetting(userSettingModel);
    }

    /**
     * 三方登录, 进行注册
     * @param userModel
     * @param userAuthModel
     * @param userSettingModel
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void authLoginRegisterUser(UserModel userModel,
                                      UserAuthModel userAuthModel,
                                      UserSettingModel userSettingModel) {
        userDao.insertUserBasicInfo(userModel);
        userSettingDao.insertUserSetting(userSettingModel);
        userAuthDao.insertUserAuth(userAuthModel);
    }

    /**
     * 记录一条三方账号记录
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void authLoginBindUser(UserAuthModel userAuthModel, UserModel userModel) {
        if (userAuthModel == null) {
            userAuthDao.insertUserAuth(userAuthModel);
        }
        userDao.updateUserBasicInfo(userModel);
    }

    /**
     * 根据三方登录唯一id 查询出该三方信息是否存在于本系统
     * @param secret
     * @param channel
     * @return
     */
    public UserAuthModel getAppointSecretUserAuth(String secret, Integer channel) {
        return userAuthDao.getAppointNot2FAUserAuth(secret, channel);
    }
}
